//
//  LevelDBCache.swift
//  
//
//  Created by tank on 2021/11/24.
//

import Foundation
import LibLevelDB

public class LevelDBCache: CacheProtocol {

    private static let db: DBManager = DBManager(dbName: "app-leveldb")

    public let path: String?


    public required init(path: String?) {
        self.path = path
    }

    public func bool(key: String) -> Bool? {
        return LevelDBCache.db.bool(forKey: cacheKey(key: key))
    }

    public func int(key: String) -> Int? {
        return LevelDBCache.db.int(forKey: cacheKey(key: key))
    }

    public func float(key: String) -> Float? {
        return Float(LevelDBCache.db.float(forKey: cacheKey(key: key)))
    }

    public func double(key: String) -> Double? {
        return LevelDBCache.db.float(forKey: cacheKey(key: key))
    }

    public func string(key: String) -> String? {
        return LevelDBCache.db.string(forKey: cacheKey(key: key))
    }
    
    public func data(key: String) -> Data? {
        return LevelDBCache.db.data(forKey: key)
    }

    public func object<T: Codable>(type: T.Type, key: String) -> T? {
        guard let data = LevelDBCache.db.data(forKey: cacheKey(key: key)) else {
            return nil
        }

        return try? CodableBuilder().createJSONDecoder().decode(type, from: data)
    }

    public func objectNSSecureCoding<T: NSSecureCoding & NSObject>(type: T.Type, key: String) -> T? {
        return LevelDBCache.db.object(forKey: cacheKey(key: key)) as? T
    }

    public func setBool(value: Bool, key: String) {
        LevelDBCache.db.setBool(value, forKey: cacheKey(key: key))
    }

    public func setInt(value: Int, key: String) {
        LevelDBCache.db.setInt(value, forKey: cacheKey(key: key))
    }

    public func setFloat(value: Float, key: String) {
        LevelDBCache.db.setFloat(Double(value), forKey: cacheKey(key: key))
    }

    public func setDouble(value: Double, key: String) {
        LevelDBCache.db.setFloat(value, forKey: cacheKey(key: key))
    }

    public func setString(value: String, key: String) {
        LevelDBCache.db.setString(value, forKey: cacheKey(key: key))
    }
    
    public func setData(value: Data, key: String) {
        LevelDBCache.db.setData(value, forKey: key)
    }

    public func setObject<T: Codable>(value: T, key: String) {
        guard let data = try? CodableBuilder().createJSONEncoder().encode(value) else {
            return
        }

        LevelDBCache.db.setData(data, forKey: cacheKey(key: key))
    }

    public func setObjectNSSecureCoding<T>(value: T, key: String) where T : NSSecureCoding {
        LevelDBCache.db.setObject(value, forKey: cacheKey(key: key))
    }

    public func remove(key: String) {
        LevelDBCache.db.removeValue(forKey: cacheKey(key: key))
    }

    public func removeAll() {
        guard let allKeys = LevelDBCache.db.allKeys() as? [String] else {
            return
        }

        allKeys.forEach { key in
            LevelDBCache.db.removeValue(forKey: cacheKey(key: key))
        }
    }
}
